package com.syni.mdd.sjb.common.component.utils.common.utils;

import lombok.extern.log4j.Log4j2;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.aop.framework.AdvisedSupport;
import org.springframework.aop.framework.AopProxy;
import org.springframework.aop.support.AopUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;

/**
 * @className AopTargetUtils
 * @description TOO
 * @Author cfx
 * @DATE 2020/4/11 17:29
 * @VERSION 1.0
 **/
@Log4j2
public class AopTargetUtils {
    /**
     * 获取 目标对象
     * @param proxy 代理对象
     * @return
     * @throws Exception
     */
    public static Object getTarget(Object proxy){
        try {
            if(!AopUtils.isAopProxy(proxy)) {
                return proxy; //不是代理对象
            }

            if(AopUtils.isJdkDynamicProxy(proxy)) {
                return getJdkDynamicProxyTargetObject(proxy);
            } else { //cglib
                return getCglibProxyTargetObject(proxy);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }


    private static Object getCglibProxyTargetObject(Object proxy) throws Exception {
        Field h = proxy.getClass().getDeclaredField("CGLIB$CALLBACK_0");
        h.setAccessible(true);
        Object dynamicAdvisedInterceptor = h.get(proxy);

        Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised");
        advised.setAccessible(true);

        Object target = ((AdvisedSupport)advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget();

        return target;
    }

    private static Object getJdkDynamicProxyTargetObject(Object proxy) throws Exception {
        Field h = proxy.getClass().getSuperclass().getDeclaredField("h");
        h.setAccessible(true);
        AopProxy aopProxy = (AopProxy) h.get(proxy);

        Field advised = aopProxy.getClass().getDeclaredField("advised");
        advised.setAccessible(true);

        Object target = ((AdvisedSupport)advised.get(aopProxy)).getTargetSource().getTarget();

        return target;
    }

    public static Class getTargetMethodReturnClass(ProceedingJoinPoint pjp){
        try {
            Object[] args = pjp.getArgs();
            Class[] paramsCls = new Class[args.length];
            for (int i = 0; i < args.length; ++i) {
                if(args[i] != null) {
                    paramsCls[i] = args[i].getClass();
                }
            }
            //获取方法
//            System.out.println(pjp.getTarget());
//            System.out.println(pjp.getTarget().getClass());
//            System.out.println(pjp.getSignature().getName());
//            System.out.println(pjp.getSignature().toString());
            Method method = pjp.getTarget().getClass().getMethod(pjp.getSignature().getName(), paramsCls);
            //获取返回值类型
            Type t = method.getAnnotatedReturnType().getType();
            Class returnClass = (Class) t;
            return returnClass;
        }catch (Exception e){
            log.error(e.getMessage(),e);
        }
        return null;
    }
}
